package com.aaa.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.aaa.dao.RedisStockDao;
import com.aaa.entity.RedisStock;
import com.aaa.service.RedisStockService;
import com.mysql.cj.util.TimeUtil;
import org.omg.CORBA.TIMEOUT;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

/**
 * (RedisStock)表服务实现类
 *
 * @author makejava
 * @since 2022-12-08 09:20:00
 */
@Service("redisStockService")
public class RedisStockServiceImpl extends ServiceImpl<RedisStockDao, RedisStock> implements RedisStockService {

    @Resource
    private RedisStockDao redisStockDao;

    /**
     * 单线程没问题,多线程下出现超卖现象
     *
     * @param id id
     * @return {@link String}
     */
    @Override
    public String decr(Integer id) {
        RedisStock stock = redisStockDao.selectById(id);
        if(stock.getNum() > 0){
            stock.setNum(stock.getNum() - 1);
            redisStockDao.updateById(stock);
            System.out.println("商品编号："+id + ",商品剩余："+ stock.getNum() + "个！");
            return "编号："+id + ",商品剩余："+ stock.getNum() + "个！";
        }else {
            System.out.println("商品编号："+id + ",商品库存不足！");
            return "编号："+id + ",商品库存不足！";
        }
    }

    /**
     * 多线程下出现超卖现象,使用同步锁进行解决
     *
     * @param id id
     * @return {@link String}
     */
    @Override
    public String decrSynchronized(Integer id) {
        synchronized (RedisStockServiceImpl.class) {
            long threadId = Thread.currentThread().getId();
            RedisStock stock = redisStockDao.selectById(id);
            if(stock.getNum() > 0){
                stock.setNum(stock.getNum() - 1);
                redisStockDao.updateById(stock);
                System.out.println("线程：" + threadId + ",商品编号："+id + ",商品剩余："+ stock.getNum() + "个！");
                return "线程：" + threadId + ",商品编号："+id + "商品剩余："+ stock.getNum() + "个！";
            }else {
                System.out.println("线程：" + threadId + ",商品编号："+id + ",商品库存不足！");
                return "线程：" + threadId + ",商品编号："+id + ",商品库存不足！";
            }
        }
    }

    @Autowired
    private RedisTemplate<String,Object> redisTemplate;

    /**
     *
     * 使用redis分布式锁解决
     * @param id id
     * @return {@link String}
     */
    @Override
    public String decrRedisTemplate(Integer id) {
        long threadId = Thread.currentThread().getId();
        ValueOperations<String, Object> forValue = redisTemplate.opsForValue();
        //获取锁对象: 如果返回true表示获取锁成功,如果返回false 获取锁失败
        Boolean val = forValue.setIfAbsent("lockKey::" + id, "val", 30, TimeUnit.SECONDS);
        if(val){
            try{
                RedisStock stock = redisStockDao.selectById(id);
                if(stock.getNum() > 0){
                    stock.setNum(stock.getNum() - 1);
                    redisStockDao.updateById(stock);
                    System.out.println("线程：" + threadId + ",商品编号："+id + ",商品剩余："+ stock.getNum() + "个！");
                    return "线程：" + threadId + ",商品编号："+id + "商品剩余："+ stock.getNum() + "个！";
                }else {
                    System.out.println("线程：" + threadId + ",商品编号："+id + ",商品库存不足！");
                    return "线程：" + threadId + ",商品编号："+id + ",商品库存不足！";
                }
            }finally {
                //释放锁资源
                redisTemplate.delete("lockKey::"+id);
            }
        }else {
            //当前线程获取锁失败---->根据业务需求。
            System.out.println("服务器正忙,请稍后再试.....");
            return "服务器正忙,请稍后再试.....";
        }
    }

    @Resource
    private RedissonClient redissonClient;


    /**
     * 使用redis第三方依赖
     *
     * @param id id
     * @return {@link String}
     */
    @Override
    public String decrRedisson(Integer id) {
        long threadId = Thread.currentThread().getId();
        // 获取锁对象
        RLock lock = redissonClient.getLock("lockKey::" + id);
        // 必须为30秒
        lock.lock(30,TimeUnit.SECONDS);
        try{
            RedisStock stock = redisStockDao.selectById(id);
            if(stock.getNum() > 0){
                stock.setNum(stock.getNum() - 1);
                redisStockDao.updateById(stock);
                System.out.println("线程：" + threadId + ",商品编号："+id + ",商品剩余："+ stock.getNum() + "个！");
                return "线程：" + threadId + ",商品编号："+id + "商品剩余："+ stock.getNum() + "个！";
            }else {
                System.out.println("线程：" + threadId + ",商品编号："+id + ",商品库存不足！");
                return "线程：" + threadId + ",商品编号："+id + ",商品库存不足！";
            }
        }finally {
            //释放锁资源
            lock.unlock();
        }
    }

}

